﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using RAD.LightOne;
using System.Threading;

namespace RAD.LightOne.Cache
{
    #region Documentation
    /// <summary>
    /// Classe que funciona como um cache de queries utilizadas na recuperação dos dados do diversos tipos de classes.
    /// Várias instâncias, cache único.
    /// ThreadSafe, Singleton
    /// </summary>
    #endregion
    internal sealed class SelectQueryCache : ICollection<KeyValuePair<string,StringBuilder>>
    {
        #region Fields

        private static Mutex mutex;
        private object locker;
        private Dictionary<string,StringBuilder> queries;
        private static SelectQueryCache instance;
        #endregion

        #region Properties

        #region Documentation
        /// <summary>
        /// Retorna uma query do cache por sua chave.
        /// </summary>
        /// <param name="key">string utilizada como chave.</param>
        /// <returns>stringBuilder contendo a string sql.</returns>
        #endregion
        [System.Runtime.CompilerServices.IndexerName("GetItem")]
        public StringBuilder this[string key]
        {
            get
            {
                lock (this.locker)
                {
                    return queries[key];
                }
            }
        }

        #endregion

        #region Constructors
        static SelectQueryCache()
        {
            mutex = new Mutex();
        }
        private SelectQueryCache()
        {
            this.locker = new object();
            this.queries = new Dictionary<string, StringBuilder>();
        }
        #endregion

        #region Methods

        #region Documentation
        ///<summary>
        /// Retorna a instância (singleton) do cache.
        ///</summary>
        #endregion
        public static SelectQueryCache Instance()
        {
            try
            {
                mutex.WaitOne();

                if (instance == null)
                {
                    instance = new SelectQueryCache();
                }

                return instance;
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }

        public bool Contains(string key)
        {
            lock (this.locker)
            {
                return queries.ContainsKey(key);
            }
        }

        #endregion

        #region ICollection<KeyValuePair<string,StringBuilder>> Members

        public void Add(KeyValuePair<string, StringBuilder> item)
        {
            lock (this.locker)
            {
                queries.Add(item.Key, item.Value);
            }
        }

        public void Clear()
        {
            lock (this.locker)
            {
                queries.Clear();
            }
        }

        public bool Contains(KeyValuePair<string, StringBuilder> item)
        {
            lock (this.locker)
            {
                return queries.ContainsKey(item.Key);
            }
        }

        public void CopyTo(KeyValuePair<string, StringBuilder>[] array, int arrayIndex)
        {
            lock (this.locker)
            {
                List<KeyValuePair<string, StringBuilder>> keysValues = new List<KeyValuePair<string, StringBuilder>>();
                lock (queries)
                {
                    string[] keys = new string[queries.Keys.Count];
                    queries.Keys.CopyTo(keys, arrayIndex);

                    StringBuilder[] values = new StringBuilder[queries.Values.Count];
                    queries.Values.CopyTo(values, arrayIndex);

                    for (int i = 0; i < keys.Length; i++)
                    {
                        keysValues.Add(new KeyValuePair<string, StringBuilder>(keys[i], values[i]));
                    }
                }

                keysValues.CopyTo(array, 0);
            }
        }

        public void CopyTo(KeyValuePair<string, StringBuilder>[] array)
        {
            this.CopyTo(array, 0);
        }

        public int Count
        {
            get { lock (this.locker) { return queries.Count; } }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public bool Remove(KeyValuePair<string, StringBuilder> item)
        {
            lock (this.locker)
            {
                return queries.Remove(item.Key);
            }
        }

        #endregion

        #region IEnumerable<KKeyValuePair<string,StringBuilder>> Members

        public IEnumerator<KeyValuePair<string, StringBuilder>> GetEnumerator()
        {
            lock (this.locker)
            {
                return queries.GetEnumerator();
            }
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            lock (this.locker)
            {
                return queries.GetEnumerator();
            }
        }

        #endregion

    }
}
